home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
dviware
/
umddvi
/
dev
/
ip.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-01
|
18KB
|
697 lines
/*
* Copyright (c) 1987 University of Maryland Department of Computer Science.
* All rights reserved. Permission to copy for any purpose is hereby granted
* so long as this copyright notice remains intact.
*/
#ifndef lint
static char rcsid[] = "$Header$";
#endif
/*
* DVI to Interpress driver
*
* Reads DVI version 2 files and converts to Xerox Interpress format.
*/
#include "types.h"
#include "dvi.h"
#include "dviclass.h"
#include "dvicodes.h"
#include "fio.h"
#include "pxl.h"
#include "search.h"
#include "interpress.h"
#include <stdio.h>
char *ProgName;
extern int errno;
extern char *optarg;
extern int optind;
/* Globals */
char serrbuf[BUFSIZ]; /* buffer for stderr */
/* DVI style arithmetic: when moving horizontally by a DVI distance >=
``space'', we are to recompute horizontal position from DVI units;
otherwise, we are to use device resolution units to keep track of
horizontal position. A similar scheme must be used for vertical
positioning. */
struct fontinfo {
struct pxltail *px; /* pxl file info */
int ipfont; /* Interpress font index */
i32 pspace; /* boundary between ``small'' & ``large''
spaces (for positive horizontal motion) */
i32 nspace; /* -4 * pspace, for negative motion */
i32 vspace; /* 5 * pspace, for vertical motion */
int cwidth[128]; /* width (in DEVs) of each char */
char cload[128]; /* flag for ``char loaded into Imagen'' */
};
int MaxDrift; /* the maximum allowable difference between
hh and SPtoDEV(dvi_h), and vv and.... */
struct search *FontFinder; /* search table for DVI index => fontinfo */
struct fontinfo *CurrentFont; /* the current font (if any) */
int NextIPFont; /* during font definition, the next ip font
index */
int FontErrors; /* true => error(s) during font definition */
char *TeXfonts; /* getenv("TEXFONTS") */
int ExpectBOP; /* true => BOP ok */
int ExpectEOP; /* true => EOP ok */
int DPI; /* -d => device resolution (dots/inch) */
/* int LFlag; /* -l => landscape mode (eventually...) */
int SFlag; /* -s => silent (no page #s) */
int XFlag; /* -x => debug (undocumented) */
int hh; /* current horizontal position, in DEVs */
int vv; /* current vertical position, in DEVs */
/* Similar to dvi_stack, but includes ``hh'' and ``vv'', which are usually
but not always the same as SPtoDEV(h) and SPtoDEV(v): */
struct localstack {
int stack_hh;
int stack_vv;
struct dvi_stack stack_dvi;
};
struct localstack *dvi_stack; /* base of stack */
struct localstack *dvi_stackp; /* current place in stack */
int HHMargin; /* horizontal margin (in DEVs) */
int VVMargin; /* vertical margin (in DEVs) */
int Numerator; /* numerator from DVI file */
int Denominator; /* denominator from DVI file */
int DVIMag; /* magnification from DVI file */
double UserMag; /* user specified magnification */
double GlobalMag; /* overall magnification (UserMag*DVIMag) */
double conv; /* conversion factor for magnified DVI units */
double OneHalf = 0.5; /* .5, so compiler can generate constant only
once */
double Zero = 0.0; /* likewise */
double _d_; /* Used to store intermediate results. The
compiler should do this for us, but it's
too stupid. */
int IpHH; /* Interpress horizontal position */
int IpVV; /* Interpress vertical position */
int IpFont; /* Interpress current-font number */
char *getenv (), *malloc ();
/* Absolute value */
#define ABS(n) ((n) >= 0 ? (n) : -(n))
/* Round a floating point number to integer */
#define ROUND(f) ((int) (_d_ = (f), \
_d_ < Zero ? _d_ - OneHalf : _d_ + OneHalf)
/* Convert to floating point */
#define FLOAT(i) ((double) (i))
/* Convert a value in sp's to dev's, and vice versa */
#define SPtoDEV(sp) (ROUND ((sp) * conv))
#define DEVtoSP(dev) (ROUND ((dev) / conv))
/* Put a two-byte (word) value */
#define putword(w) (putchar ((w) >> 8), putchar (w))
/* Correct devpos (the virtual device position) to be within MaxDrift pixels
of dvipos (the virtual DVI position). */
#define FIXDRIFT(devpos, dvipos) \
if (ABS ((devpos) - (dvipos)) <= MaxDrift); \
else \
if ((devpos) < (dvipos)) \
(devpos) = (dvipos) - MaxDrift; \
else \
(devpos) = (dvipos) + MaxDrift
/* Compute the DEV widths of the characters in the given font */
ComputeCWidths (fi)
struct fontinfo *fi;
{
register int i;
register struct chinfo *ch;
register int *cw;
ch = fi -> px -> px_info;
cw = fi -> cwidth;
i = 128;
while (--i >= 0) {
*cw++ = SPtoDEV (ch -> ch_TFMwidth);
ch++;
}
}
SelectFont (n)
int n;
{
register struct fontinfo *f;
CurrentFont = f = FindFont ((i32) n, (struct fontinfo *) 0);
CurrentFontIndex = f - FontInfo;
}
/* Start a page (process a DVI_BOP) */
/* NOTE: I'm depending on getting a BOP before any characters or rules on a
page! */
BeginPage () {
register int *i;
static int count[10]; /* the 10 counters */
static int beenhere;
if (!ExpectBOP)
error (1, 0, "unexpected BOP");
if (beenhere) {
if (!SFlag)
putc (' ', stderr);
}
else
beenhere++;
dvi_stackp = dvi_stack;
ExpectBOP = 0;
ExpectEOP++; /* set the new "expect" state */
for (i = count; i < &count[sizeof count / sizeof *count]; i++)
fGetLong (stdin, *i);
fGetLong (stdin, i); /* previous page pointer */
if (!SFlag) {
fprintf (stderr, "[%d", count[0]);
(void) fflush (stderr);
}
putchar (imP_Page); /* XXX */
IpHH = 0;
IpVV = 0;
hh = HHMargin;
vv = VVMargin;
dvi_h = DEVtoSP (hh);
dvi_v = DEVtoSP (vv);
dvi_w = 0;
dvi_x = 0;
dvi_y = 0;
dvi_z = 0;
}
/* End a page (process a DVI_EOP) */
EndPage () {
if (!ExpectEOP)
error (1, 0, "unexpected EOP");
if (!SFlag) {
putc (']', stderr);
(void) fflush (stderr);
}
ExpectEOP = 0;
ExpectBOP++;
putchar (imP_EndPage); /* XXX */
}
/* Begin XXX */
/* Store the relevant information from the DVI postamble, and set up
various internal things. */
PosotAmbleHeader (p)
register struct PostAmbleInfo *p; {
register int n;
PrevPagePointer = p -> pai_PrevPagePointer;
Numerator = p -> pai_Numerator;
Denominator = p -> pai_Denominator;
DVIMag = p -> pai_DVIMag;
/* Here we sneakily correct for the actual device resolution, so that we can
pretend that it's 200 dots per inch. */
UserMag *= FLOAT (DPI) / 200.0;
GlobalMag = DMagFactor (DVIMag) * UserMag;
/* The conversion factor is figured as follows: there are exactly n/d DVI
units per decimicron, and 254000 decimicrons per inch, and 200 pixels per
inch. Then we have to adjust this by the stated magnification. */
conv = (Numerator / 254000.0) * (200.0 / Denominator) * GlobalMag;
n = p -> pai_DVIStackSize * sizeof *dvi_stack;
dvi_stack = (struct localstack *) malloc ((unsigned) n);
if ((dvi_stackp = dvi_stack) == 0)
error (1, errno, "can't allocate %d DVI stack bytes", n);
IntGlobalMag = ROUND (GlobalMag * 1000.0);
}
/* Handle one of the font definitions from the DVI postamble. */
PostAmbleFontDef (p)
register struct PostAmbleFont *p; {
register struct fontinfo *f;
register char *s;
int def = S_CREATE | S_EXCL;
f = (struct fontinfo *) SSearch (FontFinder, p -> paf_DVIFontIndex, &def);
if (f == 0)
if (def & S_COLL)
error (1, 0, "font %d already defined", p -> paf_DVIFontIndex);
else
error (1, 0, "can't stash font %d (out of memory?)",
p -> paf_DVIFontIndex);
f -> ipfont = NextIPFont++;
s = GenPXLFileName (p -> paf_name, p -> paf_DVIMag,
p -> paf_DVIDesignSize, IntGlobalMag, TeXfonts);
if ((f -> px = ReadPXLFile (s, 1)) == 0) {
error (0, errno, "can't find font \"%s\"", s);
FontErrors++;
return;
}
if (p -> paf_DVIChecksum != f -> px -> px_checksum)
error (0, 0, "\
WARNING: width tables and raster tables have different\n\
\tchecksums for font \"%s\"\n\
\tPlease notify your TeX maintainer\n\
\t(TFM checksum = 0%o, PXL checksum = 0%o)",
s, dvi_checksum, f -> px -> px_checksum);
ScaleTFMWidths (f -> px, dvi_mag);
ComputeCWidths (f);
f -> pspace = p -> paf_DVIMag / 6; /* a three-unit ``thin space'' */
f -> nspace = -4 * f -> pspace;
f -> vspace = 5 * f -> pspace;
}
/* Read the postamble. */
ReadPostAmble () {
static char s[2] = { 's', 0 };
if ((FontFinder = SCreate (sizeof (struct fontinfo))) == 0)
error (1, 0, "can't create FontFinder (out of memory?)");
ScanPostAmble (stdin, PostAmbleHeader, PostAmbleFontDef);
if (FontErrors)
error (1, 0, "missing font%s prevent%s output (sorry)",
FontErrors > 1 ? s : &s[1], FontErrors == 1 ? s : &s[1]);
}
/* End XXX */
/* Read the preamble and do a few sanity checks */
ReadPreAmble () {
register int n;
rewind (stdin);
if (GetByte (stdin) != Sign8 (DVI_PRE))
error (1, 0, "missing PRE");
if (GetByte (stdin) != Sign8 (DVI_VERSION))
error (1, 0, "mismatched version numbers");
if (GetLong (stdin) != Numerator)
error (1, 0, "mismatched numerator");
if (GetLong (stdin) != Denominator)
error (1, 0, "mismatched denominator");
if (GetLong (stdin) != DVIMag)
error (1, 0, "mismatched \\magfactor");
n = UnSign8 (GetByte (stdin));
while (--n >= 0)
(void) GetByte (stdin);
}
main (argc, argv)
int argc;
register char **argv;
{
register int c;
char *inname;
setbuf (stderr, serrbuf);
ProgName = *argv;
UserMag = 1.0;
MaxDrift = DefaultMaxDrift;
DPI = DefaultDPI;
inname = "stdin";
while ((c = getopt (argc, argv, "d:m:r:s")) != EOF) {
switch (c) {
case 'd': /* max drift value */
MaxDrift = atoi (optarg);
break;
/* case 'l': /* landscape mode */
/* LFlag++; */
/* break; */
case 'm': /* magnification */
UserMag = DMagFactor (atoi (optarg));
break;
case 'r': /* resolution */
DPI = atoi (optarg);
break;
case 's': /* silent */
SFlag++;
break;
case 'x': /* enable debugging */
XFlag++;
break;
case '?':
fprintf (stderr, "\
Usage: %s [-d drift] [-m mag] [-s] [-r resolution] [file]\n",
ProgName);
(void) fflush (stderr);
exit (1);
}
}
if (optind < argc)
if (freopen (inname = argv[optind], "r", stdin) == NULL)
error (1, errno, "can't open %s", inname);
/* ReadPostAmble does an fseek which, if performed on a tty, tends to make
the shell log one out, thus the following kludge: */
if (isatty (fileno (stdin)))
error (1, 0, "input from ttys is expressly forbidden!");
TeXfonts = getenv ("TEXFONTS");
if (TeXfonts == 0)
TeXfonts = "";
ReadPostAmble ();
/* Margins -- needs work! */
HHMargin = DefaultLeftMargin;/* XXX */
VVMargin = DefaultTopMargin;/* XXX */
ReadPreAmble ();
ExpectBOP++;
(void) fseek (stdin, PrevPagePointer, 0);
/* All set! */
printf ("Interpress/Xerox/2.1 ");
PutInstructionsBody (inname);
PutPreamble ();
ReadDVIFile ();
/* EOF is implicit (?) */
exit (0);
}
/* Skip a font definition (since we are using those from the postamble) */
/* ARGSUSED */
SkipFontDef (font)
int font;
{
register int i;
(void) GetLong (stdin);
(void) GetLong (stdin);
(void) GetLong (stdin);
i = UnSign8 (GetByte (stdin)) + UnSign8 (GetByte (stdin));
while (--i >= 0)
(void) GetByte (stdin);
}
/* Perform a \special - right now ignore all of them */
DoSpecial (len)
int len; /* length of the \special string */
{
error (0, 0, "warning: ignoring \\special");
(void) fseek (stdin, (long) len, 1);
}
/* Draw a rule at the current (hh,vv) position. There are two 4 byte
parameters. The first is the height of the rule, and the second is the
width. (hh,vv) is the lower left corner of the rule. */
SetRule (advance)
int advance;
{
i32 rwidth, /* rule width from DVI file */
rheight; /* rule height from DVI file */
register int h,
w;
fGetLong (stdin, rheight);
fGetLong (stdin, rwidth);
/* Rule sizes must be computed in this manner: */
h = conv * rheight;
if (FLOAT (h) < (conv * rheight))
h++;
w = conv * rwidth;
if (FLOAT (w) < (conv * rwidth))
w++;
/* put the rule out */
if (IpHH != hh || IpVV != vv)
SetPosition (hh, vv);
putchar (imP_Rule); /* XXX */
putword (w); /* XXX */
putword (h); /* XXX */
putword (-h + 1); /* XXX */
if (advance) {
hh += w;
dvi_h += rwidth;
if (ABS (hh - (w = SPtoDEV (dvi_h))) > MaxDrift)
hh = w + (hh < w ? -MaxDrift : MaxDrift);
}
}
/* FIXME (kerns, etc, etc) */
/* resume XXX */
/* This rather large routine reads the DVI file and calls on other routines
to do anything moderately difficult (except put characters: there is
a bunch of ugly code with ``goto''s which makes things much faster) */
ReadDVIFile () {
register int c,
p;
int advance;
IpFamily = -1;
/* Only way out is via "return" statement */
for (;;) {
/* Get the DVI byte, and if it's a character, put it */
/* c = UnSign8 (getchar ()); */
c = getchar (); /* getchar() returns unsigned values */
if (DVI_IsChar (c)) { /* I know, ugly, but ... no function call
overhead this way */
register struct chinfo *ch;
register struct fontinfo *cf;
set:
advance = 1;
put:
cf = CurrentFont;
ch = &cf -> px -> px_info[c];
if (ch -> ch_width == 0)
goto ignore; /* not a real character, just advance */
/* BEGIN INLINE EXPANSION OF IpSetPosition (the things we do in
the name of efficency! ;-) ) */
if (ImHH != hh) {
if (ImHH == hh - 1)
putchar (imP_Forw);
else if (ImHH == hh + 1)
putchar (imP_Backw);
else {
putchar (imP_SetHAbs);
putword (hh);
}
ImHH = hh;
}
if (ImVV != vv) {
putchar (imP_SetVAbs);
putword (vv);
ImVV = vv;
}
/* END INLINE EXPANSION OF ImSetPosition */
if (ImFamily != CurrentFontIndex) {
putchar (imP_SetFamily);
putchar (CurrentFontIndex);
ImFamily = CurrentFontIndex;
}
putchar (c);
ImHH += cf -> cwidth[c];
ignore:
if (advance) {
#ifdef DEBUG
if (XFlag) {
fprintf (stderr, "setchar%d h:=%d+%d=%d, hh:=%d\n",
c, dvi_h - DEVtoSP (HHMargin), ch->ch_TFMwidth,
dvi_h - DEVtoSP (HHMargin) + ch->ch_TFMwidth,
hh + CurrentFont->cwidth[c] - HHMargin);
fflush (stderr);
}
#endif DEBUG
hh += cf -> cwidth[c];
dvi_h += ch -> ch_TFMwidth;
p = SPtoDEV (dvi_h);
FIXDRIFT (hh, p);
}
continue;
}
/* Wasn't a character, maybe a font? */
if (DVI_IsFont (c)) {
SelectFont ((i32) (c - DVI_FNTNUM0));
continue;
}
/* Wasn't a font, see if it's a generic one */
if (p = DVI_OpLen (c)) {
/* It's generic, get its parameter */
switch (p) {
case 1:
p = Sign8 (getchar ());
break;
case 2:
fGetWord (stdin, p);
p = Sign16 (p);
break;
case 3:
fGet3Byte (stdin, p);
p = Sign24 (p);
break;
case 4:
fGetLong (stdin, p);
break;
case 5:
p = UnSign8 (getchar ());
break;
case 6:
fGetWord (stdin, p);
p = UnSign16 (p);
break;
case 7:
fGet3Byte (stdin, p);
p = UnSign24 (p);
break;
}
/* Now that we have the parameter, perform the command */
switch (DVI_DT (c)) {
case DT_SET:
c = p;
goto set;
case DT_PUT:
c = p;
advance = 0;
goto put;
case DT_RIGHT:
move_right:
dvi_h += p;
/* DVItype tells us that we must round motions in this way:
``When the horizontal motion is small, like a kern, hh
changes by rounding the kern; but when the motion is
large, hh changes by rounding the true position so that
accumulated rounding errors disappear.'' */
if (p >= CurrentFont -> pspace ||
p <= CurrentFont -> nspace)
hh = SPtoDEV (dvi_h);
else {
hh += SPtoDEV (p);
p = SPtoDEV (dvi_h);
FIXDRIFT (hh, p);
}
break;
case DT_W:
dvi_w = p;
goto move_right;
case DT_X:
dvi_x = p;
goto move_right;
case DT_DOWN:
move_down:
dvi_v += p;
/* ``Vertical motion is done similarly, but with the
threshold between ``small'' and ``large'' increased by a
factor of 5. The idea is to make fractions like $1\over2$
round consistently, but to absorb accumulated rounding
errors in the baeline-skip moves.'' */
if (ABS (p) >= CurrentFont -> vspace)
vv = SPtoDEV (dvi_v);
else {
vv += SPtoDEV (p);
p = SPtoDEV (dvi_v);
FIXDRIFT (vv, p);
}
break;
case DT_Y:
dvi_y = p;
goto move_down;
case DT_Z:
dvi_z = p;
goto move_down;
case DT_FNT:
SelectFont (p);
break;
case DT_XXX:
DoSpecial (p);
break;
case DT_FNTDEF:
SkipFontDef (p);
break;
#ifdef PARANOID
default:
error (1, 0, "bad DVI_DT(%d): (%d)", c, DVI_DT (c));
#endif PARANOID
}
continue;
}
/* Wasn't a char, wasn't a generic command, just pick it out from the
whole mess */
switch (c) {
case DVI_SETRULE:
SetRule (1);
break;
case DVI_PUTRULE:
SetRule (0);
break;
case DVI_NOP:
break;
case DVI_BOP:
BeginPage ();
break;
case DVI_EOP:
EndPage ();
if (PrevPagePointer == -1) {
if (!SFlag) {
fprintf (stderr, "\n");
(void) fflush (stderr);
}
return;
}
break;
case DVI_PUSH:
dvi_stackp -> stack_hh = hh;
dvi_stackp -> stack_vv = vv;
dvi_stackp -> stack_dvi = dvi_current;
dvi_stackp++;
break;
case DVI_POP:
dvi_stackp--;
hh = dvi_stackp -> stack_hh;
vv = dvi_stackp -> stack_vv;
dvi_current = dvi_stackp -> stack_dvi;
break;
case DVI_W0:
p = dvi_w;
goto move_right;
case DVI_X0:
p = dvi_x;
goto move_right;
case DVI_Y0:
p = dvi_y;
goto move_down;
case DVI_Z0:
p = dvi_z;
goto move_down;
case DVI_PRE:
error (1, 0, "unexpected PRE");
case DVI_POST: /* shouldn't get this, reading backwards */
error (1, 0, "unexpected POST");
case DVI_POSTPOST:
error (1, 0, "unexpected POSTPOST");
default:
error (1, 0, "undefined DVI opcode (%d)", c);
}
}
}